"""
做一个通用的驱动类接口
"""
import serial
from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Tuple, Callable, Any
from enum import Enum
import time
import threading

from app.dev_com.usb_to_can_protocol import (UsbCanProtocol,CANFrame, RecvQueue,
                                  UsbCanParamFrame, UsbCanParamFuncCode, UsbCanErrorFrame,UsbCanRWCode, FrameFactory)

from app.utils.utils import Utils,Data_Utils

# ==================== 基础类型定义 ====================
class CommType(Enum):
    """通信类型枚举"""
    RS232 = "rs232"
    RS485 = "rs485"
    CAN   = "can"
    TCP   = "tcp"
    UDP   = "udp"
    
class CommStatus(Enum):
    """通信状态枚举"""
    CLOSED     = "closed"       # 已关闭
    CONNECTING = "connecting"   # 连接中
    CONNECTED  = "connected"    # 已连接
    ERROR      = "error"        # 错误状态
    TIMEOUT    = "timeout"      # 超时
    
class CommConfig:
    """通信配置基类"""
    def __init__(self,node, timeout: float = 1.0, retry_count: int = 3):
        self.node = node
        self.timeout = timeout
        self.retry_count = retry_count
        
class SerialConfig(CommConfig):
    """串口配置"""
    def __init__(self, name: str = ""):
        super().__init__(node = 1, timeout=1, retry_count=3)
        self.name = name
        self.port = ""
        self.baudrate = 0
        self.bytesize = 8
        self.parity = 'N'
        self.stopbits = 1
        self.auto_check_cmd = [] #自动识别COM口的命令
        
        suc, msg = self.load()
        if not suc:
            raise Exception(f"加载配置失败: {msg}")
        
    def load(self) -> Tuple[bool, str]:
        """从配置文件加载配置
        
 
            
        Returns:
            Tuple[bool, str]: (成功标志, 消息)
        """
        import json
        import os
        
        try:
            # 构建配置文件路径
            config_file = Utils.get_config_file_path("device_comm.cfg")
            
            # 检查文件是否存在
            if not os.path.exists(config_file):
                return False, f"配置文件不存在: {config_file}"
            
            # 读取配置文件
            with open(config_file, 'r', encoding='utf-8') as f:
                config_data = json.load(f)
            
            # 检查配置名称是否存在
            if self.name not in config_data:
                available_configs = list(config_data.keys())
                return False, f"配置名称 '{self.name}' 不存在，可用配置: {available_configs}"
            
            # 加载配置数据
            cfg = config_data[self.name]
            
            # 设置必需参数
            if "port" in cfg:
                self.port = cfg["port"]
            if "baudrate" in cfg:
                self.baudrate = cfg["baudrate"]
                
            # 设置可选参数
            if "bytesize" in cfg:
                self.bytesize = cfg["bytesize"]
            if "parity" in cfg:
                self.parity = cfg["parity"]
            if "stopbits" in cfg:
                self.stopbits = cfg["stopbits"]
            if "timeout" in cfg:
                self.timeout = cfg["timeout"]
            if "retry_count" in cfg:
                self.retry_count = cfg["retry_count"]
            if "auto_check_cmd" in cfg:
                self.auto_check_cmd = cfg["auto_check_cmd"]
                
            return True, f"成功加载配置 '{self.name}'"
            
        except json.JSONDecodeError as e:
            return False, f"配置文件JSON格式错误: {e}"
        except Exception as e:
            return False, f"加载配置失败: {e}"
        
    def save(self) -> Tuple[bool, str]:
        """保存配置到文件
        
 
        Returns:
            Tuple[bool, str]: (成功标志, 消息)
        """
        import json
        import os
        
        try:
            # 确定配置名称
 
            if not self.name:
                return False, "未指定配置名称"
            
            # 构建配置文件路径
            config_file = Utils.get_config_file_path("device_comm.cfg")
            
            # 读取现有配置文件
            config_data = {}
            if os.path.exists(config_file):
                try:
                    with open(config_file, 'r', encoding='utf-8') as f:
                        config_data = json.load(f)
                except json.JSONDecodeError:
                    # 如果文件格式错误，创建新的配置
                    config_data = {}
            
            # 更新配置数据
            config_data[self.name] = {
                "name": self.name,
                "port": self.port,
                "baudrate": self.baudrate,
                "bytesize": self.bytesize,
                "parity": self.parity,
                "stopbits": self.stopbits,
                "timeout": self.timeout,
                "retry_count": self.retry_count,
                "auto_check_cmd": self.auto_check_cmd
            }
            
            # 确保配置目录存在
            config_dir = os.path.dirname(config_file)
            os.makedirs(config_dir, exist_ok=True)
            
            # 保存配置文件
            with open(config_file, 'w', encoding='utf-8') as f:
                json.dump(config_data, f, indent=4, ensure_ascii=False)
            
      
            
            return True, f"成功保存配置 '{self.name}' 到 {config_file}"
            
        except Exception as e:
            return False, f"保存配置失败: {e}"
    
    def get_config_list(self) -> Tuple[bool, List[str], str]:
        """获取可用的配置列表
        
        Returns:
            Tuple[bool, List[str], str]: (成功标志, 配置名称列表, 消息)
        """
        import json
        import os
        
        try:
            # 构建配置文件路径
            config_file = Utils.get_config_file_path("device_comm.cfg")
            
            # 检查文件是否存在
            if not os.path.exists(config_file):
                return False, [], f"配置文件不存在: {config_file}"
            
            # 读取配置文件
            with open(config_file, 'r', encoding='utf-8') as f:
                config_data = json.load(f)
            
            config_names = list(config_data.keys())
            return True, config_names, f"找到 {len(config_names)} 个配置"
            
        except json.JSONDecodeError as e:
            return False, [], f"配置文件JSON格式错误: {e}"
        except Exception as e:
            return False, [], f"读取配置列表失败: {e}"
    
    def __str__(self) -> str:
        """字符串表示"""
        return (f"SerialConfig(name='{self.name}', port='{self.port}', "
                f"baudrate={self.baudrate}, node={self.node})")

        

        
class NetworkConfig(CommConfig):
    """网络配置"""  
    def __init__(self, host: str, port: int, **kwargs):
        super().__init__(**kwargs)
        self.host = host
        self.port = port
    
# ==================== 传输层接口 ====================
class TransportInterface(ABC):
    """传输层抽象接口 - 负责底层数据传输"""
    def __init__(self, name: str, config: CommConfig):
        self.name = name
        self.config = config
        self.connected = False
        self.last_error = ""
        self.status = CommStatus.CLOSED
        
        
    
    @abstractmethod
    def open(self) -> Tuple[bool, str]:
        """连接传输层"""
        pass
    
    @abstractmethod  
    def close(self) -> Tuple[bool, str]:
        """断开连接"""
        pass
    
    @abstractmethod
    def is_connected(self) -> bool:
        """检查连接状态"""
        pass
    
    @abstractmethod
    def _send_raw(self, data: list[int]) -> Tuple[bool, str]:
        """发送原始数据"""
        pass
    
    @abstractmethod
    def recv_raw(self, timeout: Optional[float] = None) -> Tuple[bool, list[int], str]:
        """接收原始数据"""
        pass
    
    # @abstractmethod
    # def get_status(self) -> CommStatus:
    #     """获取传输状态"""
    #     pass

# ==================== 协议层接口 ====================

class ProtocolInterface(ABC):
    """协议层抽象接口 - 负责数据封包和协议处理"""
    
    def __init__(self, transport: TransportInterface):
        self.transport = transport
    
    @abstractmethod
    def encode_request(self, node_id: int, addr: int, data: Any) -> Tuple[bool, bytes, str]:
        """编码请求数据"""
        pass
    
    @abstractmethod
    def decode_response(self, raw_data: bytes) -> Tuple[bool, Any, str]:
        """解码响应数据"""
        pass
    
    @abstractmethod
    def validate_response(self, req_data: bytes, rsp_data: bytes) -> Tuple[bool, str]:
        """验证响应有效性"""
        pass   
        
# ==================== 硬件层通信接口 ====================
class Comm_Interface(ABC):
    
    def __init__(self, name: str):
        self.name = name
        self._status = CommStatus.CLOSED
        
    @property
    @abstractmethod
    def is_open(self) -> bool: ...
    
    @abstractmethod
    def open(self) -> Tuple[bool, str]: ...
    
    @abstractmethod
    def close(self) -> Tuple[bool, str]: ...
   
    @abstractmethod
    def write(self,data: list[int]) -> Tuple[bool, str]: ...

    @abstractmethod
    def recv(self) -> Tuple[bool, List[int], str]:...
    

    def write_async(self, data: List[int],
                   callback: Callable[[bool, str], None] = None) -> bool:
        """异步写入数据"""
        import threading
        def _async_write():
            suc, msg = self.write(data)
            if callback:
                callback(suc, msg)
        
        thread = threading.Thread(target=_async_write)
        thread.daemon = True  
        thread.start()
        return True
    
    
# =====================串口Serial通信(硬件层)===========================
import queue
class Serial_Comm(Comm_Interface):
    def __init__(self, name: str, config: SerialConfig):
        super().__init__(name)
        self.config = config
        self.ser = None
        
        # self.recv_queue = queue.Queue()
        self.recv_data_list = []
        self.is_recving  = False #是否在接收数据
        
    def _msg(self, msg) -> str:
        return f"[{self.name}] {msg}"
    
    # def _bytes_to_hex_str(self, data: bytes) -> str:
    #     """将bytes转换为Hex字符串，空格分隔"""
    #     return ' '.join([f'{b:02X}' for b in data])
        
    @property
    def is_open(self) -> bool:
        """判断串口是否打开"""
        return self.ser is not None and self.ser.is_open
    
    def open(self) -> Tuple[bool | str]:
        if self.is_open:
            return True, "already opened"
        
        
        try:
            self.ser = serial.Serial(port=self.config.port, 
                                     baudrate=self.config.baudrate, 
                                     bytesize=self.config.bytesize,
                                     parity=self.config.parity,
                                     stopbits=self.config.stopbits,
                                     timeout=self.config.timeout)
        except Exception as e:
            return False, self._msg(f"connect fail; {str(e)}")
        
        return self.ser.is_open, f"{self.name} connect {self.ser.is_open}"
    
    def close(self) -> Tuple[bool , str]:
        """关闭串口"""
        if self.is_open:
            self.ser.close()
            
        return True, "ok"
    
    def write(self, data: list[int]) -> Tuple[bool , str]:
        """发送"""
        try:
            if not self.is_open:
                return False, self._msg("send data fail, serial not open.")
            print(f"send_data:[{' '.join([f'{byte:02X}' for byte in data])}]")
            self.ser.write(bytes(data))
            return True, "ok"
        except Exception as e:
            self.close()
            return False, self._msg(f"send data fail, data[{data}]; {str(e)}")
        
    
    def recv(self, timeout = 0.010) -> Tuple[bool , list[int], str]:
        """接收"""
        if not self.is_open:
            return False, [], self._msg("recv data fail, serial not open.")
        
        try:
            time_start = time.time()
            while time.time() - time_start < timeout:
                # time.sleep(0.01)
                if self.ser.in_waiting > 0:
                    # print("11111")
                    self.is_recving = True
                    data_bytes = self.ser.read_all()
                    print(f"serial recv data: [{' '.join([f'{byte:02X}' for byte in data_bytes])}]")
                    # self.recv_queue.put(data_bytes)
                    self.is_recving = False
                    return True, list(data_bytes), "ok"
                time.sleep(0.001)
                self.is_recving = False
            return False, [], self._msg("recv data timeout.")
        except Exception as e:
            self.close()
            return False, [], self._msg(f"recv data fail, {str(e)}")
    
    
#======================================传输层============================================
from pymodbus.client import ModbusSerialClient
from pymodbus.framer import FramerType
import threading
class Modbus_Serial_Comm(TransportInterface):
    """Modbus RTU 的串口通信
    """
    def __init__(self, name: str, config: SerialConfig):
        super().__init__(name, config)
        self.config = config
        self.modbus_client = None
        self.lock = threading.Lock()
    
    def _msg(self, msg) -> str:
        return f"[{self.name}] {msg}"
        
    def is_connected(self) -> bool:
        return self.modbus_client is not None and self.modbus_client.connected
        
    def open(self) -> Tuple[bool , str]:
        
        if self.is_connected():
            return True, "ok"
        
        suc, port, msg = Modbus_Serial_Comm._auto_connect(self.config)
        if not suc:
            return False, self._msg(msg)
        self.config.port = port
        self.config.save()
        return self._m_connect()
    
    
    def close(self) -> Tuple[bool , str]:
        
        if self.is_connected():
            self.modbus_client.close()
        self.modbus_client = None
        return True, "ok"
    
        
    def _check_dev(self) -> Tuple[bool , str]: 
        """检查COM口是否正确"""
        data_list = self._list_str_to_list(self.config.auto_check_cmd)
        if data_list is None:
            return False, self._msg(f"auto check cmd error, cmd=[{self.config.auto_check_cmd}]")
        suc, _, msg = self.send_and_recv_raw_data(data_list)
        if not suc:
            return False, msg
        return True, "ok"

    def modbus_read_registers(self, node:int, address:int, count :int) -> Tuple[bool, list[int], str]:
                         
        """通用步进驱动通信
        
        return : success, list[values], msg
        """
        with self.lock:
            if not self.is_connected():
                suc, msg = self._m_connect()
                if not suc:
                    return False, [], "modbus client not connected." + msg

            try:
                response = self.modbus_client.read_holding_registers(slave=node,
                                                    address=address, 
                                                    count=count
                                                    )
                if response.isError():
                    return False, None, self._msg(f"node[{node}]读取寄存器失败,{response}")
                if count != len(response.registers):
                    return False, None, self._msg(f"node[{node}]读取寄存器数量不匹配,target=[{count}], actual=[{len(response.registers)}]")
                else:
                    return True, response.registers, f"node[{node}] Success"
            except Exception as e:
                return False, None, self._msg(" modbus read exception; " + str(e))

    #test done
    def modbus_write_registers(self, node:int, address:int, count :int, values: list[int] =[0],) -> Tuple[bool, str]:
                         
        """通用步进驱动通信
        
        return : success, msg
        """
        with self.lock:
            if not self.is_connected():
                return False, self._msg("modbus client not connected.")
            
            if values is None:
                return False, self._msg(f"node[{node}] 通信写入操作需要提供 'values'")
            
            if count != len(values):
                return False, self._msg(f"node[{node}] 写入操作需要提供 'values=[{values}]' 的长度与 'count'=[{count}] 相同")
            
            try:
                if count == 1:
                    response = self.modbus_client.write_register(slave=node, 
                                                address=address, 
                                                value=values[0])
                else:
                    response = self.modbus_client.write_registers(slave=node, 
                                                    address=address,
                                                    values=values)
                    
                if response.isError():
                    return False, self._msg(f"node[{node}] 写入寄存器失败, {response}")
                else:
                    return True, "ok" 
            except Exception as e:
                return False, self._msg(" modbus write exception; " + str(e))

    def _send_raw(self, request : list[int]) -> Tuple[bool, str]:
        """发送原始数据"""
        try:
            if not self.is_connected():
                return False, self._msg("serial not connected.")
        
            #发送数据
            resp = self.modbus_client.send(request=bytes(request))
            if resp <= 0:
                return False, [], self._msg("send raw data error")
            
            return True, "ok"
        except Exception as e:
            return False, str(e)
        
    def recv_raw(self, timeout = 0.1) -> Tuple[bool , list[int] , str]:
        try:
            if not self.is_connected():
                return False, self._msg("serial not connected.")

            start_time = time.time()
            while time.time() - start_time < timeout:
                if self.modbus_client._in_waiting() <= 0:               
                        continue
                if self.modbus_client._in_waiting() > 0:
                    time.sleep(0.02)
                    break

            resp = self.modbus_client.recv(size=None)   #加上size，试一试效果，LK的通讯有时候会丢数据
            if resp is None or len(resp) == 0:
                return False,[], self._msg(f"recv raw data error, {resp}")
            
            return True, list(resp), "Success"
        except Exception as e:
            return False, [], str(e)
            
            
    def send_and_recv_raw_data(self, request : list[int], 
                                       recv_wait_time:int =  0.01,
                                       need_ack : bool = True) -> Tuple[bool, list[int], str]:
        """发送原始数据"""
        with self.lock:
            try:
                if not self.is_connected():
                    return False, self._msg("serial not connected.")
            
                #发送数据
                suc, msg = self._send_raw(bytes(request))
                if not suc:
                    return suc, [], msg
                
                if not need_ack:
                    return True, [], "ok"

                #接收数据
                time.sleep(recv_wait_time)

                return self.recv_raw(timeout= 0.1)
            
            except Exception as e:
                return False, [], str(e)

    def _list_str_to_bytes(self, str_list: List[str]) -> Optional[bytes]:
        """将十六进制字符串列表转换为bytes"""
        try:
            # 如果是 ["01", "03", "00", "00"] 格式
            return bytes([int(s, 16) for s in str_list])
        except ValueError as e:
            return None
        
    def _list_str_to_list(self, str_list: List[str]) -> Optional[list[int]]:
        """将十六进制字符串列表转换为bytes"""
        try:
            # 如果是 ["01", "03", "00", "00"] 格式
            return [int(s, 16) for s in str_list]
        except ValueError as e:
            return None
        
    def _m_connect(self, need_check_port = True) -> Tuple[bool , str]:
        """连接串口"""
        try:
            if self.is_connected():
                return False, "serial is connected"
                
            self.modbus_client  = ModbusSerialClient(framer  = FramerType.RTU,
                                                    port     = self.config.port,
                                                    baudrate = self.config.baudrate,
                                                    bytesize = self.config.bytesize,
                                                    stopbits = self.config.stopbits,
                                                    parity   = self.config.parity,
                                                    timeout  = self.config.timeout)
            if self.modbus_client is None:
                return False, f"Failed to open serial port [{self.config.port}]"
            
            suc =  self.modbus_client.connect()
            if suc :
                if need_check_port:
                    """对设备进行通讯检查"""
                    suc, msg = self._check_dev()
                    if not suc:
                        self.close()  #通信失败，断开连接
                        return False, msg
                return True, "connect ok"
            else:
                return False, "connect fail"
        except Exception as e:
            return False, self._msg(f"Failed to open port [{self.port}], {str(e)}")
        
    @classmethod
    def _auto_connect(cls, config:SerialConfig)-> Tuple[bool, str, str]:
        """自动识别可用的串口通讯"""

        ports = cls._get_available_ports()
        if ports is None or len(ports) == 0:
            return False,"", "[error] no serial ports list to connect"
        
        serial : cls = None
        """端口不对的情况下,对port端口进行检查"""
        for port in ports:
            config.port = port
            serial = cls(config.name, config)
            suc, msg = serial._m_connect()
            if suc:
                serial.close()
                return True, port, "ok"
            
        return False,"", msg
        
    @staticmethod
    def _get_available_ports() -> list:
        """获取可用的串口列表"""
        ports = [port.device for port in serial.tools.list_ports.comports()]
        return ports


class RS_Comm(TransportInterface):
    """RS232/RS485通信,都可以使用这个类"""
    def __init__(self, name: str, config: CommConfig):
        super().__init__(name, config)
        self.config = config
        self.serial = Modbus_Serial_Comm("RS232", config)
        
    def open(self) -> Tuple[bool , str]:
        return self.serial.open()
    
    def close(self) -> Tuple[bool, str]:
        """断开连接"""
        return self.serial.close()
    
 
    def is_connected(self) -> bool:
        """检查连接状态"""
        return self.serial.is_connected()
    
 
    def _send_raw(self, data_list: list[int]) -> Tuple[bool, str]:
        """发送原始数据"""
        return self.serial._send_raw(data_list)
    
 
    def recv_raw(self, timeout: float = 0.1) -> Tuple[bool, list[int], str]:
        """接收原始数据"""
        return self.serial.recv_raw(timeout) 

    def send_and_recv(self, data_list : list[int]) -> Tuple[bool, list[int], str]:
        return self.serial.send_and_recv_raw_data(data_list)
    
    def write_register(self, addr, count, data : list[int]) -> Tuple[bool, str]:
        return self.serial.modbus_write_registers(self.config.node, addr, count, data)
    
    def read_register(self, addr, count) -> Tuple[bool, list[int], str]:
        return self.serial.modbus_read_registers(self.config.node, addr, count=count)

    
# =====================Can通信===========================


class USBConfig(CommConfig):
    """USB配置"""
    def __init__(self, name: str = ""):
        super().__init__(name)
        self.host_id = 0
        self.usb_vid = 2020
        self.usb_pid = 2025
        


class CANConfig(CommConfig):
    """CAN配置"""
    def __init__(self, name: str = ""):
        super().__init__(name)
        self.host_id = 0
        self.channel = 1 # 1
        self.bitrate = 500000
        suc, msg = self.load()
        if not suc:
            # config_default.save()
            print(msg)

    
    def load(self) -> Tuple[bool, str]:
        """从配置文件加载配置
        
 
            
        Returns:
            Tuple[bool, str]: (成功标志, 消息)
        """
        import json
        import os
        
        try:
            # 构建配置文件路径
            config_file =  Utils.get_config_file_path("device_comm.cfg")
            
            # 检查文件是否存在
            if not os.path.exists(config_file):
                return False, f"配置文件不存在: {config_file}"
            
            # 读取配置文件
            with open(config_file, 'r', encoding='utf-8') as f:
                config_data = json.load(f)
            
            # 检查配置名称是否存在
            if self.name not in config_data:
                available_configs = list(config_data.keys())
                return False, f"配置名称 '{self.name}' 不存在，可用配置: {available_configs}"
            
            # 加载配置数据
            cfg = config_data[self.name]
            
            # 设置必需参数
            if "host_id" in cfg:
                self.host_id = cfg["host_id"]
            if "bitrate" in cfg:
                self.bitrate = cfg["bitrate"]
                
            if "test_cmd" in cfg:
                self.test_cmd = cfg["test_cmd"]
            
            return True, f"成功加载配置 '{self.name}'"
            
        except json.JSONDecodeError as e:
            return False, f"配置文件JSON格式错误: {e}"
        except Exception as e:
            return False, f"加载配置失败: {e}"
        
    def save(self) -> Tuple[bool, str]:
        """保存配置到文件
        
 
        Returns:
            Tuple[bool, str]: (成功标志, 消息)
        """
        import json
        import os
        
        try:
            # 确定配置名称
 
            if not self.name:
                return False, "未指定配置名称"
            
            # 构建配置文件路径
            config_file = Utils.get_config_file_path("device_comm.cfg")
            
            # 读取现有配置文件
            config_data = {}
            if os.path.exists(config_file):
                try:
                    with open(config_file, 'r', encoding='utf-8') as f:
                        config_data = json.load(f)
                except json.JSONDecodeError:
                    # 如果文件格式错误，创建新的配置
                    config_data = {}
            
            # 更新配置数据
            config_data[self.name] = {
                "name": self.name,
                "host_id": self.host_id,
                "bitrate": self.bitrate,
            }
            
            # 确保配置目录存在
            config_dir = os.path.dirname(config_file)
            os.makedirs(config_dir, exist_ok=True)
            
            # 保存配置文件
            with open(config_file, 'w', encoding='utf-8') as f:
                json.dump(config_data, f, indent=4, ensure_ascii=False)
            
      
            
            return True, f"成功保存配置 '{self.name}' 到 {config_file}"
            
        except Exception as e:
            return False, f"保存配置失败: {e}"
    
    def get_config_list(self) -> Tuple[bool, List[str], str]:
        """获取可用的配置列表
        
        Returns:
            Tuple[bool, List[str], str]: (成功标志, 配置名称列表, 消息)
        """
        import json
        import os
        
        try:
            # 构建配置文件路径
            config_file = Utils.get_config_file_path("device_comm.cfg")
            
            # 检查文件是否存在
            if not os.path.exists(config_file):
                return False, [], f"配置文件不存在: {config_file}"
            
            # 读取配置文件
            with open(config_file, 'r', encoding='utf-8') as f:
                config_data = json.load(f)
            
            config_names = list(config_data.keys())
            return True, config_names, f"找到 {len(config_names)} 个配置"
            
        except json.JSONDecodeError as e:
            return False, [], f"配置文件JSON格式错误: {e}"
        except Exception as e:
            return False, [], f"读取配置列表失败: {e}"
    
    def __str__(self) -> str:
        """字符串表示"""
        return (f"SerialConfig(name='{self.name}', port='{self.port}', "
                f"baudrate={self.baudrate}, node={self.test_cmd})")
    
# config_default = CANConfig("CAN1")
# config_default.host_id = 0
# config_default.bitrate = 500000


class Dev_UsbToCan(TransportInterface):
    """USB CAN通信类"""
    def __init__(self, name: str):
        self._ser_config = SerialConfig(name=name)
        super().__init__(name, self._ser_config)
        
        self._serial          = None  #Serial_Comm("usbcan", config)
        self._protocol        = UsbCanProtocol()
        self._recv_queue      = RecvQueue()
        self._recv_thread     = None
        self._recv_running    = False
        self._recv_queue_lock = threading.Lock()  #队列处理锁，一次只能有一个在使用
        
        self._recv_data_list = []

    def _msg(self, msg) -> str:
        return f"[{self.name}] {msg}"
 
    def open(self) -> Tuple[bool, str]:
        """连接传输层"""
        #1 使用config的port进行连接测试
        config_port_is_available = True
        ser = None
        try:
            print(f"connect port: {self._ser_config.port}")
            ser = serial.Serial(port=self._ser_config.port, baudrate=self._ser_config.baudrate, timeout=0.1)
            if ser is not None:
                if not ser.is_open:
                    ser.open()
                suc, msg = self._check_dev(ser)
                if suc:
                    #当前的端口可以连上设备
                    config_port_is_available = True
                else:
                    #当前的端口不能连上设备
                    config_port_is_available = False
                ser.close()
        except Exception as e:
            if ser is not None:
                if ser.is_open:
                    ser.close()
            config_port_is_available = False
            print("port is not available")
            
        #2 如果config的端口不能连上设备，则自动识别串口
        if not config_port_is_available:
            # 自动识别串口
            suc, port, msg = self._auto_detect_port(self._ser_config) 
            if not suc:
                return suc, msg
            self._ser_config.port = port
            
            if not suc:
                return suc, msg
            
        suc, msg = self._ser_config.save() #这里保存配置一次 
        #3 串口类初始化
        self._serial = Serial_Comm("usbcan", self._ser_config)    
        suc, msg = self._serial.open()
        if suc:
            # 启动接收线程
            self._start_recv_thread()
        print(f"open usbcan success, port: {self._ser_config.port}")
        return suc, msg
    
    def _auto_detect_port(self, config:SerialConfig)-> Tuple[bool, str, str]:
        """自动识别可用的串口通讯"""

        ports = Utils.get_available_ports()
        if ports is None or len(ports) == 0:
            return False,"", "[error] no serial ports list to connect"
        
        """端口不对的情况下,对port端口进行检查"""
        for port in ports:
            config.port = port
            print(f"port: {port} check")
            try:
                ser = serial.Serial(port=port, baudrate=config.baudrate, timeout=0.1)
            except Exception as e:
                print(f"[auto_detect_port] {port} is not available: {e}")
                continue
            if not ser.is_open:
                ser.open()
            suc, msg = self._check_dev(ser)
            ser.close()
            if suc:
                print(f"port: {port} ok")
                return True, port, "ok"
            
        return False,"", msg
    
    def _check_dev(self, ser: serial.Serial) -> Tuple[bool , str]: 
        """检查COM口是否正确"""
        data_list = Data_Utils.list_str_to_list(self._ser_config.auto_check_cmd.split(" "))
        if data_list is None:
            return False, self._msg(f"auto check cmd error, cmd=[{self._ser_config.auto_check_cmd}]")
        suc = ser.write(bytes(data_list))
        if not suc:
            return False, "write error"
        time.sleep(0.1)
        data_list = ser.read_all()
        if data_list is None or len(data_list) == 0:
            return False, "read error"
        return True, "ok"
    
    def close(self) -> Tuple[bool, str]:
        """断开连接"""
        # 停止接收线程
        self._stop_recv_thread()
        return self._serial.close()
    
    @property
    def is_connected(self) -> bool:
        """检查连接状态"""
        if self._serial is None:
            return False
        return self._serial.is_open
    
    def _send_raw(self, data: list[int]) -> Tuple[bool, str]:
        """发送原始数据"""
        return self._serial.write(data)
    
    # def recv_raw(self, timeout: float = 0.1) -> Tuple[bool, list[int], str]:
    #     """接收原始数据"""
    #     return self.serial.recv(timeout)
    
    def recv_raw(self, timeout: float = 0.1) -> Tuple[bool, list[int], str]:
        """接收原始数据"""
        suc, frame, msg = self.recv_can_frame(timeout)
        if suc:
            return True, frame.data, msg
        else:
            return False, [], msg    
        
    def send_can_msg(self, can_id : int, data : list[int], is_ext_id = False) -> Tuple[bool, str]:
        """发送CAN消息"""
        can_frame = CANFrame(can_id = can_id, 
                             data = data, 
                             dlc = len(data), 
                             is_extended = is_ext_id)
        return self.send_can_frame(can_frame)
        
    def send_can_frame(self, can_frame: CANFrame) -> Tuple[bool, str]:
        """发送CAN帧"""
        try:
            frame_bytes = self._protocol.unpack_can_frame_to_data(can_frame)
            return self._send_raw(frame_bytes)
        except Exception as e:
            return False, self._msg(f"发送CAN帧失败: {e}")
    
    def recv_can_frame(self, timeout: float = 0.01) -> Tuple[bool, CANFrame, str]:
        """接收CAN帧"""
        start_time = time.time()
        while time.time() - start_time < timeout:
            with self._recv_queue_lock:
                frame = self._recv_queue.pop()
                if frame and not isinstance(frame, CANFrame):
                    self._recv_queue.put(frame)
                    continue
                elif frame and isinstance(frame, CANFrame):
                    return True, frame, "ok"
                time.sleep(0.001)
        return False, None, self._msg(f"接收CAN帧超时-{timeout}s")
    
    def recv_param_raw_data(self, timeout: float = 1.0) -> Tuple[bool, list[int], str]:
        """接收参数帧"""
        start_time = time.time()
        while time.time() - start_time < timeout:
            with self._recv_queue_lock:
                frame = self._recv_queue.pop()
                if frame and isinstance(frame, UsbCanParamFrame):
                    return True, frame.data, "ok"
                elif frame and not isinstance(frame, UsbCanParamFrame):
                    print(f"[recv_param_raw_data] re-put frame to recv_queue.")
                    self._recv_queue.put(frame)
                else:
                    time.sleep(0.001)
        return False, None, self._msg(f"接收参数帧超时-{timeout}s")
    
    def _start_recv_thread(self):
        """启动接收线程"""
        if self._recv_thread is None or not self._recv_thread.is_alive():
            self._recv_running = True
            self._recv_thread = threading.Thread(target=self._usbcan_recv_threading, daemon=True)
            self._recv_thread.start()
    
    def _stop_recv_thread(self):
        """停止接收线程"""
        self._recv_running = False
        if self._recv_thread and self._recv_thread.is_alive():
            self._recv_thread.join(timeout=1.0)
    
    def _usbcan_recv_threading(self):
        """接收工作线程"""
        while self._recv_running and self.is_connected:
            try:
                with self._recv_queue_lock:
                    suc, data_list, msg = self._serial.recv(timeout=0.005)
                    if suc and data_list:
                        # 解包数据帧
                        self._recv_data_list.extend(data_list)
                        suc, frame_list, msg = self._protocol.pack_recv_data_to_frame(self._recv_data_list)
                        if suc and frame_list:
                            print(f"[recv threading] put frame to recv_queue.")
                            for frame in frame_list:
                                if isinstance(frame, CANFrame):
                                    self._recv_data_list = self._recv_data_list[16:]
                                elif isinstance(frame, UsbCanParamFrame):
                                    self._recv_data_list = self._recv_data_list[12:]
                                elif isinstance(frame, UsbCanErrorFrame):
                                    self._recv_data_list = self._recv_data_list[8:]
                                else:
                                    self._recv_data_list = self._recv_data_list[1:]
                                self._recv_queue.put(frame)
                        else:
                            print(f"[recv threading] pack frame error: {msg}")
                time.sleep(0.001)
            except Exception as e:
                if self._recv_running:
                    print(self._msg(f"接收线程异常: {e}"))
            

    def set_bitrate(self, bitrate : int) -> Tuple[bool, str]:
        """设置CAN波特率"""
        try:
            send_data = [0]*7 + [bitrate]
            param = UsbCanParamFrame(func_code=UsbCanParamFuncCode.BitRate.value,
                                     read_write=UsbCanRWCode.WRITE.value,
                                     data=send_data)
            
            send_list = self._protocol.unpack_param_frame_to_data(param)
            suc, msg = self._send_raw(send_list)
            if not suc:
                return False, self._msg(f"设置CAN波特率失败: {msg}")
            
            # 等待确认响应
            suc, recv_data, msg = self.recv_param_raw_data(timeout=5.0)
            if not suc:
                return False, self._msg(f"设置CAN波特率失败，无响应: {msg}")
            
            print(f"param data: [{' '.join([f'{byte:02X}' for byte in recv_data])}]")
            
            if send_data != recv_data:
                return False, self._msg(f"设置CAN波特率失败，响应错误")
            
            
            return True, self._msg(f"设置CAN波特率成功")

        except Exception as e:
            return False, self._msg(f"设置CAN波特率异常: {e}")
        
        
    def get_bitrate(self) -> Tuple[bool, int, str]:
        """获取CAN波特率"""
        try:
            data = [0]*8
            param = UsbCanParamFrame(func_code=UsbCanParamFuncCode.BitRate.value,
                                     read_write=UsbCanRWCode.READ.value,
                                     data=data)
            
            send_list = self._protocol.unpack_param_frame_to_data(param)
            suc, msg = self._send_raw(send_list)
            if not suc:
                return False, 0, self._msg(f"获取CAN波特率失败: {msg}")
            
            suc, recv_list, msg = self.recv_param_raw_data(timeout=5.0)
            if not suc:
                return False, 0, self._msg(f"获取CAN波特率失败，无响应: {msg}")
            
            print(f"get bitrate data: [{' '.join([f'{byte:02X}' for byte in recv_list])}]")
            
            return True, recv_list[7], self._msg(f"获取CAN波特率成功")
        except Exception as e:
            return False, 0, self._msg(f"获取CAN波特率异常: {e}")
        
        

    def get_recv_queue_size(self) -> int:
        """获取接收队列大小"""
        return self._recv_queue.size()
    
    def clear_recv_queue(self):
        """清空接收队列"""
        self._recv_queue.clear()

# =====================NetWork通信===========================


#------------------------Usb Can 使用示例---------------------------------
usbcan_comm = Dev_UsbToCan("usbcan")